# tools.py
# 基础工具、参数模型与错误类型定义（Pydantic v2）
from __future__ import annotations
from typing import Any, Dict, List
from pydantic import BaseModel, Field
import random

# ---- 错误分层 ----
class ToolError(Exception):
    """通用工具错误。"""

class TransientToolError(ToolError):
    """可重试的瞬时错误（网络抖动、上游超时）。"""

class FatalToolError(ToolError):
    """不可恢复的致命错误（权限、资源缺失、语义前置条件不满足）。"""


# ---- 示例工具：加法 ----
class AddArgs(BaseModel):
    a: float
    b: float

def add_tool(args: AddArgs) -> float:
    return args.a + args.b


# ---- 示例工具：迷你“搜索” ----
CORPUS = [
    "向量数据库用于相似度搜索，常见有FAISS、Milvus、PGVector。",
    "检索增强生成（RAG）通过检索外部知识提升回答的可靠性。",
    "多智能体（Multi-Agent）强调角色分工与协作。",
    "MCP 标准化了工具与资源的暴露与发现。",
    "ReAct 让模型先思考再行动，提升可追踪性。"
]

class SearchArgs(BaseModel):
    query: str = Field(min_length=1, description="关键词")
    top_k: int = Field(default=3, ge=1, le=5, description="返回条数（1~5）")

def _flaky() -> None:
    """以 20% 概率触发瞬时错误，用于演示重试逻辑。"""
    if random.random() < 0.2:
        raise TransientToolError("transient: upstream timeout")

def search_tool(args: SearchArgs) -> List[str]:
    _flaky()
    q = args.query.strip().lower()
    hits = [t for t in CORPUS if q in t.lower()]
    return hits[: args.top_k]

def repair_search_args(raw: Dict[str, Any]) -> Dict[str, Any]:
    """示例性“参数修复”：top_k 转换/夹逼，query 清洗。"""
    fixed = dict(raw)
    if "top_k" in fixed:
        try:
            fixed["top_k"] = int(float(fixed["top_k"]))
        except Exception:
            fixed["top_k"] = 3
        fixed["top_k"] = max(1, min(5, fixed["top_k"]))
    if "query" in fixed and isinstance(fixed["query"], str):
        fixed["query"] = fixed["query"].strip()
    return fixed
